/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

#include "common/lang/comparator.h"
#include "common/log/log.h"
#include "common/type/date_type.h"
#include "common/type/data_type.h"
#include "common/type/attr_type.h"
#include "common/value.h"
#include <cstdint>
#include <cstdlib>
#include <iomanip>
#include <regex>
#include <string>

#define date int32_t

int DateType::compare(const Value &left, const Value &right) const
{
  //我们假设左侧一定为date
  ASSERT(left.attr_type() == AttrType::DATES, "invalid type for date");
  ASSERT(right.attr_type() == AttrType::DATES || right.attr_type() == AttrType::CHARS, "invalid type for date or string");
  date left_date_value = left.get_date();
  date right_date_value = right.get_date();
  return common::compare_int(
      (void *)&left_date_value, (void *)&right_date_value);
}

RC DateType::cast_to(const Value &val, AttrType type, Value &result) const
{
  switch (type) {
    case AttrType::CHARS:{
      result.set_type(type);
      std::string s;
      to_string(val, s);
      result.set_string(s.c_str());
      return RC::SUCCESS;
    }break;
    default: return RC::UNIMPLEMENTED;
  }
  return RC::SUCCESS;
}

int DateType::cast_cost(AttrType type)
{
  if (type == AttrType::DATES) {
    return 0;
  }else if(type == AttrType::CHARS){
    return 2;
  }
  return INT32_MAX;
}

RC DateType::set_value_from_str(Value &val, const string &data) const
{
  // 定义正则表达式模式
  std::regex date_regex(R"((\d{4})-(\d{1,2})-(\d{1,2}))");

  // 检查日期是否匹配正则表达式
  bool flag = 0;
  int year, month, day = 0;
  const std::string &dataStr = data;
  std::smatch matches;
  flag = std::regex_match(dataStr, matches, date_regex);
  if (!flag) {
    LOG_ERROR("date 日期正则表达匹配不对");
    return RC::INVALID_ARGUMENT;
  }
  //用流匹配
  //std::stringstream ss(dataStr);
  //char dash;
  //这里我们用正则直接实现匹配
  year = atoi(matches[1].str().c_str());
  month = atoi(matches[2].str().c_str());
  day = atoi(matches[3].str().c_str());

  //处理异常数据 包含月份异常和日期异常 同时要考虑闰年
  auto isVaildDate = [](int year, int month, int day) ->bool{
    if (month < 1 || month > 12 || day < 1 || day > 31 || year < 1) {
      return false;
    }
    switch (month){
      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12:
        return day <= 31; break;
      case 4:
      case 6:
      case 9:
      case 11:
        return day <= 30; break;
      case 2:
        if (year % 400 == 0 || (year % 4 == 0 && year % 100 !=0)) {
          return day <= 29;
        }
        return day <= 28;
      default: return false; //这里不应该到达
    }
  };

  if (!isVaildDate(year, month, day)) {
    LOG_WARN("date 日期不合法");
    return RC::INVALID_ARGUMENT;
  }
  val.set_date(year * 10000 + month *100 + day);
  return RC::SUCCESS;
}

RC DateType::to_string(const Value &val, string &result) const
{
  stringstream ss;
  char dash = '-';
  int year = val.value_.int_value_/10000;
  int month = (val.value_.int_value_ % 10000) /100;
  int day = val.value_.int_value_ % 100;
  
  ss << year << dash << std::setw(2) << std::setfill('0') << month << dash << std::setw(2) << std::setfill('0') << day;
  result = ss.str();
  return RC::SUCCESS;
}